
namespace Patterns4Net.Tests.Core.AttributePatterns
{
    using System;
    using System.Linq;
    using Mono.Cecil;
    using NUnit.Framework;
    using Attributes.DesignPatterns;
    using Patterns4Net.Core.AttributesPatterns;
    using Patterns4Net.Core.CecilExtensions;
    using Patterns4Net.Core.Patterns;

    [TestFixture]
    public class WrapperCreatorTest : WrapperCreator<Adapter>
    {
        [Test]
        public void Constructs_Adapter_With_AdapterType_And_AdapteeType()
        {
            var ctor = typeof(ProxyAttribute).GetTypeDefinition().Methods.First(x => x.IsConstructor);
            var attr = new CustomAttribute(ctor);
            AddAttribute(attr, "Adaptee", typeof (Wrapped).GetTypeDefinition());

            var result = this.Crate(attr, typeof(AdapterInstance).GetTypeDefinition());

            Assert.IsInstanceOf<Adapter>(result);
            Assert.AreEqual(((Adapter)result).AdapterType.Name, "AdapterInstance");
            Assert.AreEqual(((Adapter)result).AdapteeType.Name, "Wrapped");
            Assert.IsNull(((Adapter)result).TargetType);
        }

        [Test]
        public void Constructs_Adapter_With_AdapterType_And_TargetType()
        {
            var ctor = typeof(ProxyAttribute).GetTypeDefinition().Methods.First(x => x.IsConstructor);
            var attr = new CustomAttribute(ctor);
            AddAttribute(attr, "Target", typeof(IComparable).GetTypeDefinition());

            var result = this.Crate(attr, typeof(AdapterInstance).GetTypeDefinition());

            Assert.IsInstanceOf<Adapter>(result);
            Assert.AreEqual(((Adapter)result).AdapterType.Name, "AdapterInstance");
            Assert.AreEqual(((Adapter)result).TargetType.Name, "IComparable");
            Assert.IsNull(((Adapter)result).AdapteeType);
        }

        [Test]
        public void Constructs_Adapter_Only_With_AdapterType()
        {
            var ctor = typeof(AdapterAttribute).GetTypeDefinition().Methods.First(x => x.IsConstructor);
            var attr = new CustomAttribute(ctor);
            var result = this.Crate(attr, typeof(AdapterInstance).GetTypeDefinition());

            Assert.IsInstanceOf<Adapter>(result);
            Assert.AreEqual(((Adapter)result).AdapterType.Name, "AdapterInstance");
            Assert.IsNull(((Adapter)result).AdapteeType);
            Assert.IsNull(((Adapter)result).TargetType);
        }

        private static void AddAttribute(CustomAttribute attr, string name, object value)
        {
            attr.Properties.Add(
                new CustomAttributeNamedArgument(
                    name,
                    new CustomAttributeArgument(
                        value.GetType().GetTypeDefinition(),
                        value)));            
        }

        public class Wrapped
        {            
        }

        public class AdapterInstance : IComparable
        {
            private Wrapped w = new Wrapped();

            public int CompareTo(object obj)
            {
                return obj == w ? 0 : 1;
            }
        }

        protected override string TargetInterfacePropertyName
        {
            get { return "Target"; }
        }

        protected override string WrappedTypePropertyName
        {
            get { return "Adaptee"; }
        }
    }
}
